#include "mainwnd.h"
#include "painter.h"
#include "twitch.h"
#include "base/file.h"
#include "frameui/fontsys.h"
#include "resource.h"
#include "app.h"
#include "kappa64/interface.h"
#include "overlay.h"
#include <windowsx.h>

#define IDC_INAME       100
#define IDC_IPASS       101
#define IDC_ICHAN       102
#define IDC_IRECT       103
#define IDC_IBACKCOLOR  104
#define IDC_IBACKALPHA  105
#define IDC_ITEXTCOLOR  106
#define IDC_ITEXTFONT   107
#define IDC_IPROCLIST   108
#define IDC_IATTACH     109
#define IDC_ICONNECT    110
#define IDC_IPOSLOCKED  111
#define IDC_IPOSRESET   112
#define IDC_IOAUTHTIP   113
#define IDC_ITOGGLEKEY  114
#define IDC_IHIDDEN     115
#define IDC_IPORT       116
#define IDC_IREPLYKEY   117

class RectWindow : public WindowFrame
{
  int resizing;
  RECT rsRect;
  POINT rsPoint;
  uint32 onMessage(uint32 message, uint32 wParam, uint32 lParam);
public:
  RectWindow(Frame* parent, OverlayPainter* painter, int id);

  OverlayPainter* painter;
};
enum {
  RESIZE_LEFT     = 0x01,
  RESIZE_TOP      = 0x02,
  RESIZE_RIGHT    = 0x04,
  RESIZE_BOTTOM   = 0x08,

  RESIZE_SCROLL   = 0x10,

  RESIZE_BORDER   = 8,
};
uint32 RectWindow::onMessage(uint32 message, uint32 wParam, uint32 lParam)
{
  switch (message)
  {
  case WM_LBUTTONDOWN:
    rsPoint.x = GET_X_LPARAM(lParam);
    rsPoint.y = GET_Y_LPARAM(lParam);
    resizing = 0;
    if (painter->getScrollRect(&rsRect))
    {
      if (rsPoint.x >= rsRect.left && rsPoint.x < rsRect.right &&
          rsPoint.y >= rsRect.top && rsPoint.y < rsRect.bottom)
        resizing = RESIZE_SCROLL;
    }
    if (resizing == 0 && painter->getTargetRect(&rsRect))
    {
      if (rsPoint.x >= rsRect.left && rsPoint.x < rsRect.right &&
          rsPoint.y >= rsRect.top && rsPoint.y < rsRect.bottom)
      {
        if (rsPoint.x < rsRect.left + RESIZE_BORDER) resizing |= RESIZE_LEFT;
        if (rsPoint.y < rsRect.top + RESIZE_BORDER) resizing |= RESIZE_TOP;
        if (rsPoint.x >= rsRect.right - RESIZE_BORDER) resizing |= RESIZE_RIGHT;
        if (rsPoint.y >= rsRect.bottom - RESIZE_BORDER) resizing |= RESIZE_BOTTOM;
        if (resizing == 0) resizing = RESIZE_LEFT | RESIZE_TOP | RESIZE_RIGHT | RESIZE_BOTTOM;
      }
    }
    if (resizing)
      SetCapture(hWnd);
    break;
  case WM_MOUSEMOVE:
    if (resizing)
    {
      int dx = GET_X_LPARAM(lParam) - rsPoint.x;
      int dy = GET_Y_LPARAM(lParam) - rsPoint.y;
      rsPoint.x += dx;
      rsPoint.y += dy;

      if (resizing == RESIZE_SCROLL)
      {
        rsRect.top += dy;
        painter->setScrollTop(rsRect.top);
      }
      else
      {
        if (resizing & RESIZE_LEFT) rsRect.left += dx;
        if (resizing & RESIZE_TOP) rsRect.top += dy;
        if (resizing & RESIZE_RIGHT) rsRect.right += dx;
        if (resizing & RESIZE_BOTTOM) rsRect.bottom += dy;
        painter->setTargetRect(&rsRect);
      }
    }
    break;
  case WM_LBUTTONUP:
    if (resizing)
    {
      resizing = 0;
      ReleaseCapture();
    }
  case WM_PAINT:
    {
      PAINTSTRUCT ps;
      HDC hDC = BeginPaint(hWnd, &ps);

      Image& preview = painter->getPreview();

      HDC hbDC = CreateCompatibleDC(hDC);
      HBITMAP hBitmap = preview.createBitmap(hDC);
      SelectObject(hbDC, hBitmap);
      BitBlt(hDC, 0, 0, preview.width(), preview.height(), hbDC, 0, 0, SRCCOPY);
      DeleteDC(hbDC);
      DeleteObject(hBitmap);

      EndPaint(hWnd, &ps);
    }
    break;
  case WM_ERASEBKGND:
    return TRUE;
  default:
    return M_UNHANDLED;
  }
  return 0;
}
RectWindow::RectWindow(Frame* parent, OverlayPainter* op, int id)
  : WindowFrame(parent)
  , painter(op)
  , resizing(0)
{
  create(L"", WS_CHILD, WS_EX_CLIENTEDGE);
}

StaticFrame* MainWnd::addTip(Frame* frame, wchar_t const* text)
{
  StaticFrame* tip = new StaticFrame(text, this);
  tip->setPoint(PT_RIGHT, frame, PT_LEFT, -5, -1);
  return tip;
}

static int KeyModifiers(int k)
{
  int res = 0;
  k >>= 8;
  if (k & HOTKEYF_ALT)
    res |= MOD_ALT;
  if (k & HOTKEYF_CONTROL)
    res |= MOD_CONTROL;
  if (k & HOTKEYF_SHIFT)
    res |= MOD_SHIFT;
  return res;
}

MainWnd::MainWnd(OverlayPainter* op, TwitchClient* cl)
  : painter(op)
  , client(cl)
  , connected(false)
  , hHook(NULL)
  , hMouseHook(NULL)
  , hKeyboardHook(NULL)
  , mouseThread(0)
  , attached64(FALSE)
  , hTargetProcess(NULL)
  , idInterface(0)
  , oldPID(0)
  , overlay(NULL)
  , hIcon(LoadIcon(getInstance(), MAKEINTRESOURCE(IDI_KAPPA)))
{
  if (WNDCLASSEX* wcx = createclass(L"MainWndClass"))
  {
    wcx->hbrBackground = HBRUSH(COLOR_BTNFACE + 1);
    wcx->hCursor = LoadCursor(NULL, IDC_ARROW);
    wcx->hIcon = hIcon;
    RegisterClassEx(wcx);
  }
  create(CW_USEDEFAULT, 0, 400, 500, L"KappaUI Launcher",
    (WS_OVERLAPPEDWINDOW & (~WS_MAXIMIZEBOX)) | WS_CLIPCHILDREN, WS_EX_CONTROLPARENT);

  OverlayParams& params = painter->getParams();

  iPort = new EditFrame(this, IDC_IPORT);
  iPort->setPoint(PT_TOPLEFT, 100, 10);
  iPort->setPoint(PT_RIGHT, -10, 0);
  iPort->setHeight(21);
  iPort->setText(WideString((int) params.port));
  addTip(iPort, L"Port");

  iName = new EditFrame(this, IDC_INAME);
  iName->setPoint(PT_TOPLEFT, iPort, PT_BOTTOMLEFT, 0, 4);
  iName->setPoint(PT_RIGHT, -10, 0);
  iName->setHeight(21);
  iName->setText(params.nick);
  addTip(iName, L"Name");

  iPass = new EditFrame(this, IDC_IPASS);
  iPass->setPoint(PT_TOPLEFT, iName, PT_BOTTOMLEFT, 0, 4);
  iPass->setPoint(PT_RIGHT, -10, 0);
  iPass->setHeight(21);
  iPass->setText(params.pass);
  {
    StaticFrame* tip = new StaticFrame(L"Oauth ", this);
    LinkFrame* tipLink = new LinkFrame(L"(?)", this, IDC_IOAUTHTIP);
    tipLink->setPoint(PT_RIGHT, iPass, PT_LEFT, -5, -1);
    tip->setPoint(PT_RIGHT, tipLink, PT_LEFT, 0, 0);
  }

  iChan = new EditFrame(this, IDC_ICHAN);
  iChan->setPoint(PT_TOPLEFT, iPass, PT_BOTTOMLEFT, 0, 4);
  iChan->setPoint(PT_RIGHT, -10, 0);
  iChan->setHeight(21);
  iChan->setText(params.chan);
  addTip(iChan, L"Channel");

  iConnect = new ButtonFrame(L"Connect", this, IDC_ICONNECT, BS_PUSHLIKE | BS_CHECKBOX);
  iConnect->setPoint(PT_TOPLEFT, iChan, PT_BOTTOMLEFT, 0, 4);
  iConnect->setSize(120, 21);

  iRect = new RectWindow(this, painter, IDC_IRECT);
  iRect->setPoint(PT_TOP, iConnect, PT_BOTTOM, 0, 4);
  iRect->setPoint(PT_LEFT, 10, 0);
  iRect->setPoint(PT_RIGHT, -10, 0);

  iBackColor = new ColorFrame(Image::clr(params.background) & 0xFFFFFF, this, IDC_IBACKCOLOR);
  iBackColor->setSize(120, 21);
  addTip(iBackColor, L"Background");

  iBackAlpha = new SliderFrame(this, IDC_IBACKALPHA);
  iBackAlpha->setRange(0, 255);
  iBackAlpha->setPos((params.background >> 24) & 0xFF);
  iBackAlpha->setLineSize(8);
  iBackAlpha->setPageSize(64);
  iBackAlpha->setTicFreq(64);
  iBackAlpha->setSize(120, 41);
  iBackAlpha->setPoint(PT_LEFT, iBackColor, PT_RIGHT, 5, 0);

  iTextColor = new ColorFrame(Image::clr(params.textColor) & 0xFFFFFF, this, IDC_ITEXTCOLOR);
  iTextColor->setSize(120, 21);
  addTip(iTextColor, L"Text");

  iTextFont = new ButtonFrame(L"Font", this, IDC_ITEXTFONT);
  iTextFont->setSize(120, 21);
  iTextFont->setPoint(PT_LEFT, iTextColor, PT_RIGHT, 5, 0);

  iProcList = new ComboFrameEx(this, IDC_IPROCLIST);
  iProcList->setWidth(120);
  addTip(iProcList, L"Target");

  iAttach = new ButtonFrame(L"Attach", this, IDC_IATTACH, BS_PUSHLIKE | BS_CHECKBOX);
  iAttach->setSize(120, 21);
  iAttach->setPoint(PT_LEFT, iProcList, PT_RIGHT, 5, 0);

  iPosReset = new ButtonFrame(L"Reset", this, IDC_IPOSRESET);
  iPosReset->setSize(120, 21);
  addTip(iPosReset, L"Position");

  iReplyKey = new HotkeyFrame(this, IDC_IREPLYKEY);
  iReplyKey->setSize(120, 21);
  iReplyKey->setKey(params.replyHotkey);
  addTip(iReplyKey, L"Reply hotkey");

  iPosLocked = new ButtonFrame(L"Interactive", this, IDC_IPOSLOCKED, BS_AUTOCHECKBOX);
  iPosLocked->setSize(120, 21);
  iPosLocked->setPoint(PT_LEFT, iReplyKey, PT_RIGHT, 5, 0);
  iPosLocked->setCheck(!params.lockPosition);

  iToggleKey = new HotkeyFrame(this, IDC_ITOGGLEKEY);
  iToggleKey->setSize(120, 21);
  iToggleKey->setKey(params.toggleHotkey);
  addTip(iToggleKey, L"Toggle hotkey");

  iHidden = new ButtonFrame(L"Hidden", this, IDC_IHIDDEN, BS_AUTOCHECKBOX);
  iHidden->setSize(120, 21);
  iHidden->setPoint(PT_LEFT, iToggleKey, PT_RIGHT, 5, 0);

  iToggleKey->setPoint(PT_BOTTOMLEFT, 100, -10);
  iReplyKey->setPoint(PT_BOTTOMLEFT, iToggleKey, PT_TOPLEFT, 0, -4);
  iPosReset->setPoint(PT_BOTTOMLEFT, iReplyKey, PT_TOPLEFT, 0, -4);
  iProcList->setPoint(PT_BOTTOMLEFT, iPosReset, PT_TOPLEFT, 0, -4);
  iTextColor->setPoint(PT_BOTTOMLEFT, iProcList, PT_TOPLEFT, 0, -4);
  iBackColor->setPoint(PT_BOTTOMLEFT, iTextColor, PT_TOPLEFT, 0, -14);
  iRect->setPoint(PT_BOTTOM, iBackColor, PT_TOP, 0, -14);

  padding = height() - iRect->height();

  if (params.toggleHotkey)
    RegisterHotKey(hWnd, 0, KeyModifiers(params.toggleHotkey), params.toggleHotkey & 0xFF);

  client->setMainWnd(this);
  painter->setMainWnd(this);
  SetTimer(hWnd, NULL, 250, NULL);

  PROCESS_INFORMATION pi;
  STARTUPINFO info;
  GetStartupInfo(&info);
  WideString cmdline = WideString::format(L"kappa64.dat %d", int(hWnd));
  if (CreateProcess(L"kappa64.dat", cmdline.getBuffer(),
    NULL, NULL, FALSE, 0, NULL, NULL, &info, &pi))
  {
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    idInterface = pi.dwThreadId;
  }
}
MainWnd::~MainWnd()
{
  delete overlay;
  UnregisterHotKey(hWnd, 0);
  RemoveHook(hMouseHook);
  RemoveHook(hKeyboardHook);
  RemoveHook(hHook);
  if (hTargetProcess) CloseHandle(hTargetProcess);
  if (idInterface)
    PostThreadMessage(idInterface, WM_QUIT, 0, 0);
  client->disconnect();
}

#define WM_ADDMESSAGE       (WM_USER+109)
struct TwitchMessage
{
  int type;
  String name;
  String text;
};
void MainWnd::addMessage(int type, char const* name, char const* text)
{
  TwitchMessage* msg = new TwitchMessage;
  msg->type = type;
  msg->name = (name ? name : "");
  msg->text = (text ? text : "");
  PostMessage(hWnd, WM_ADDMESSAGE, (uint32) msg, 0);
}

void MainWnd::setConnected(bool con)
{
  connected = con;
  iName->enable(!connected);
  iPass->enable(!connected);
  iChan->enable(!connected);
  iConnect->setCheck(connected);
  if (connected)
    iConnect->setText(L"Disconnect");
  else
    iConnect->setText(L"Connect");
}
void MainWnd::attach(int i)
{
  mouseThread = 0;
  RemoveHook(hMouseHook);
  RemoveHook(hKeyboardHook);
  RemoveHook(hHook);
  hHook = NULL;
  hMouseHook = NULL;
  hKeyboardHook = NULL;
  hTargetProcess = NULL;
  delete overlay; overlay = NULL;
  attached64 = FALSE;
  if (hTargetProcess) CloseHandle(hTargetProcess);
  if (i >= 0 && proclist[i].is64)
  {
    if (idInterface)
    {
      attached64 = TRUE;
      iProcList->disable();
      iAttach->setCheck(true);
      iAttach->setText(L"Detach");
      PostThreadMessage(idInterface, KAPPA64_REQUEST_HOOK, proclist[i].pID, proclist[i].tID);
    }
  }
  else if (i >= 0 && proclist[i].pID)
  {
    hHook = InstallHook(proclist[i].tID);
    if (hHook)
    {
      hTargetProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, proclist[i].pID);
      iProcList->disable();
      iAttach->setCheck(true);
      iAttach->setText(L"Detach");
    }
    else
    {
      iProcList->enable();
      iAttach->setCheck(false);
      iAttach->setText(L"Attach");
    }
  }
  else if (i >= 0)
  {
    overlay = new OverlayWindow(painter, iPosLocked->checked());
    iProcList->disable();
    iAttach->setCheck(true);
    iAttach->setText(L"Detach");
  }
  else
  {
    if (attached64 && idInterface)
      PostThreadMessage(idInterface, KAPPA64_REQUEST_UNHOOK, 0, 0);
    iProcList->enable();
    iAttach->setCheck(false);
    iAttach->setText(L"Attach");
  }
}
uint32 MainWnd::onMessage(uint32 message, uint32 wParam, uint32 lParam)
{
  switch (message)
  {
  case WM_SETFOCUS:
    break;
  case WM_ADDMESSAGE:
    {
      TwitchMessage* msg = (TwitchMessage*) wParam;
      painter->addMessage(msg->type, msg->name, msg->text);
      delete msg;
    }
    break;
  case WM_COMMAND:
    {
      int id = LOWORD(wParam);
      int code = HIWORD(wParam);
      switch (id)
      {
      case IDC_IPORT:
        painter->getParams().port = iPort->getText().toInt();
        break;
      case IDC_INAME:
        GetWindowText(iName->getHandle(), painter->getParams().nick, 256);
        break;
      case IDC_IPASS:
        GetWindowText(iPass->getHandle(), painter->getParams().pass, 256);
        break;
      case IDC_ICHAN:
        GetWindowText(iChan->getHandle(), painter->getParams().chan, 256);
        break;
      case IDC_ICONNECT:
        setConnected(!connected);
        if (connected)
        {
          painter->addMessage(CHAT_CLEAR, NULL, NULL);
          painter->addMessage(CHAT_SYSTEM, NULL, "Connecting...");
          client->connect(String(iName->getText()), String(iPass->getText()),
            "#" + String(iChan->getText()), iPort->getText().toInt());
        }
        else
        {
          client->disconnect();
          painter->addMessage(CHAT_SYSTEM, NULL, "Disconnected");
        }
        break;
      case IDC_IBACKCOLOR:
        {
          OverlayParams& params = painter->getParams();
          params.background = (params.background & 0xFF000000) | (Image::clr(iBackColor->getColor()) & 0x00FFFFFF);
          painter->updateParams();
        }
        break;
      case IDC_ITEXTCOLOR:
        {
          OverlayParams& params = painter->getParams();
          params.textColor = Image::clr(iTextColor->getColor());
          painter->updateParams();
        }
        break;
      case IDC_ITEXTFONT:
        {
          OverlayParams& params = painter->getParams();
          LOGFONT lf;
          FontSys::getLogFont(&lf, params.fontSize, params.fontFace);

          CHOOSEFONT cf;
          memset(&cf, 0, sizeof cf);
          cf.lStructSize = sizeof cf;
          cf.hwndOwner = hWnd;
          cf.lpLogFont = &lf;
          cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_NOSCRIPTSEL | CF_SCREENFONTS;
          if (ChooseFont(&cf))
          {
            params.fontSize = (lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight);
            wcscpy(params.fontFace, lf.lfFaceName);
            painter->updateParams();
          }
        }
        break;
      case IDC_IATTACH:
        {
          if (hHook || attached64 || overlay)
            attach(-1);
          else
          {
            int sel = iProcList->getCurSel();
            if (sel >= 0) sel = iProcList->getItemData(sel);
            if (sel >= 0 && sel < proclist.length())
              attach(sel);
          }
        }
        break;
      case IDC_IPOSLOCKED:
        painter->getParams().lockPosition = !iPosLocked->checked();
        if (overlay)
          overlay->setInteractive(iPosLocked->checked());
        if (!iPosLocked->checked())
        {
          if (!attached64)
          {
            RemoveHook(hMouseHook);
            RemoveHook(hKeyboardHook);
            hMouseHook = NULL;
            hKeyboardHook = NULL;
          }
          else if (idInterface)
            PostThreadMessage(idInterface, KAPPA64_REQUEST_UNHOOKMOUSE, 0, 0);
        }
        else
        {
          if (!attached64)
          {
            RemoveHook(hMouseHook);
            RemoveHook(hKeyboardHook);
            hMouseHook = InstallMouseHook(mouseThread);
            hKeyboardHook = InstallKeyboardHook(mouseThread);
          }
          else if (idInterface)
            PostThreadMessage(idInterface, KAPPA64_REQUEST_HOOKMOUSE, 0, mouseThread);
        }
        break;
      case IDC_IPOSRESET:
        painter->resetPos();
        break;
      case IDC_IOAUTHTIP:
        ShellExecute(NULL, L"open", L"http://twitchapps.com/tmi/", NULL, NULL, SW_SHOWNORMAL);
        break;
      case IDC_ITOGGLEKEY:
        if (code == EN_CHANGE)
        {
          OverlayParams& params = painter->getParams();
          if (params.toggleHotkey)
            UnregisterHotKey(hWnd, 0);
          params.toggleHotkey = iToggleKey->getKey();
          if (params.toggleHotkey)
            RegisterHotKey(hWnd, 0, KeyModifiers(params.toggleHotkey), params.toggleHotkey & 0xFF);
        }
        break;
      case IDC_IREPLYKEY:
        if (code == EN_CHANGE)
        {
          painter->getParams().replyHotkey = iReplyKey->getKey();
          painter->updateParams();
        }
        break;
      case IDC_IHIDDEN:
        painter->setHidden(iHidden->checked() ? 1 : 0);
        break;
      }
    }
    return 0;
  case WM_HOTKEY:
    if (wParam == 0)
    {
      int h = !painter->hidden();
      painter->setHidden(h);
      iHidden->setCheck(h != 0);
    }
    break;
  case WM_HSCROLL:
    {
      OverlayParams& params = painter->getParams();
      params.background = (params.background & 0x00FFFFFF) | ((iBackAlpha->getPos() & 0xFF) << 24);
      painter->updateParams();
    }
    break;
  case TCM_DISCONNECTED:
    if (connected)
    {
      setConnected(false);
      client->disconnect();
      painter->addMessage(CHAT_SYSTEM, NULL, "Disconnected");
    }
    return 0;
  case WM_DESTROY:
    client->disconnect();
    PostQuitMessage(0);
    return 0;
  case WM_TIMER:
    {
      painter->update();
      static int counter = -1;
      counter++;
      if ((counter & 7) == 0 && !SendMessage(iProcList->getHandle(), CB_GETDROPPEDSTATE, 0, 0))
      {
        int oldPos = iProcList->getCurSel();
        if (oldPos >= 0) oldPos = iProcList->getItemData(oldPos);
        if (oldPos >= 0 && oldPos < proclist.length())
          oldPID = proclist[oldPos].pID;
        else
          oldPID = 0;
        int npos = -1;
        proclist.clear();
        ProcessEntry& self = proclist.push();
        self.hIcon = hIcon;
        self.pID = self.tID = 0;
        self.is64 = false;
        wcscpy(self.name, L"Overlay window");
        EnumProcesses(proclist);
        iProcList->reset();
        iProcList->enable(hHook == NULL && !attached64 && overlay == NULL);
        for (int i = 0; i < proclist.length(); i++)
        {
          int pos = iProcList->addString(proclist[i].name, proclist[i].hIcon, i);
          if (proclist[i].pID == oldPID)
            npos = pos;
        }
        if (npos >= 0)
          iProcList->setCurSel(npos);
        else if (proclist.length())
          iProcList->setCurSel(0);
        else
          iProcList->disable();
        if (idInterface)
          PostThreadMessage(idInterface, KAPPA64_REQUEST_LISTPROC, (WPARAM) hWnd, 0);
      }
      DWORD code;
      if (hTargetProcess && GetExitCodeProcess(hTargetProcess, &code) && code != STILL_ACTIVE)
        attach(-1);
    }
    return 0;
  case WM_SIZING:
    {
      RECT* rc = (RECT*) lParam;
      if (rc->right - rc->left < 365)
      {
        if (wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT)
          rc->left = rc->right - 365;
        else
          rc->right = rc->left + 365;
      }
      int height = getHeight(rc->right - rc->left);
      if (height)
      {
        if (wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT)
          rc->top = rc->bottom - height;
        else
          rc->bottom = rc->top + height;
      }
      return TRUE;
    }
  case WM_SIZE:
    updateImage();
    return 0;

  case KAPPA64_RESPONSE_LOST:
    attach(-1);
  case KAPPA64_RESPONSE_LISTPROC:
    {
      for (int i = 0; i < proclist.length(); i++)
        if (proclist[i].pID == lParam)
          return 0;
      if (hHook == NULL && !attached64 && overlay == NULL)
        iProcList->enable();
      int index = proclist.length();
      ProcessEntry& pe = proclist.push();
      GetProcessInfo((HWND) wParam, pe);
      pe.is64 = TRUE;
      int pos = iProcList->addString(pe.name, pe.hIcon, index);
      if (pe.pID == oldPID)
        iProcList->setCurSel(pos);
      else if (proclist.length() == 1)
        iProcList->setCurSel(0);
    }
    break;

  case WM_UPDATEREPLY:
    painter->updateReply();
    break;
  case WM_POSTREPLY:
    painter->postReply();
    break;

  default:
    return M_UNHANDLED;
  }
  return 0;
}
int MainWnd::getHeight(int width)
{
  HWND hTarget = painter->getTargetWnd();
  RECT trc = {0, 0, 0, 0};
  if (hTarget)
    GetClientRect(hTarget, &trc);
  if (trc.right == 0 || trc.bottom == 0)
  {
    trc.right = GetSystemMetrics(SM_CXSCREEN);
    trc.bottom = GetSystemMetrics(SM_CYSCREEN);
  }

  RECT adjFrame, adjImage;
  memset(&adjFrame, 0, sizeof adjFrame);
  memset(&adjImage, 0, sizeof adjImage);
  AdjustWindowRectEx(&adjFrame, WS_CAPTION, NULL, 0);
  AdjustWindowRectEx(&adjImage, 0, NULL, WS_EX_CLIENTEDGE);
  width += adjFrame.left - adjFrame.right;
  width -= 20;
  width += adjImage.left - adjImage.right;
  width = width * trc.bottom / trc.right;
  width += adjImage.bottom - adjImage.top;
  width += padding;
  width += adjFrame.bottom - adjFrame.top;
  return width;
}
void MainWnd::updateImage()
{
  RECT rc;
  GetWindowRect(hWnd, &rc);
  int height = getHeight(rc.right - rc.left);
  if (height && height != rc.bottom - rc.top)
    SetWindowPos(hWnd, NULL, 0, 0, rc.right - rc.left, height, SWP_NOMOVE | SWP_NOZORDER);

  if (GetForegroundWindow() == hWnd)
    iRect->invalidate();
}
SIZE MainWnd::previewSize()
{
  RECT rc;
  GetClientRect(iRect->getHandle(), &rc);
  SIZE sz;
  sz.cx = rc.right;
  sz.cy = rc.bottom;
  return sz;
}
void MainWnd::setTargetThread(DWORD id)
{
  if (iPosLocked->checked() && mouseThread != id)
  {
    mouseThread = id;
    if (hHook)
    {
      RemoveHook(hMouseHook);
      RemoveHook(hKeyboardHook);
      hMouseHook = InstallMouseHook(id);
      hKeyboardHook = InstallKeyboardHook(id);
    }
    else if (attached64 && idInterface)
      PostThreadMessage(idInterface, KAPPA64_REQUEST_HOOKMOUSE, 0, id);
  }
}

void MainWnd::updateOverlay()
{
  if (overlay)
    overlay->update(NULL);
}
